/**
 * @widoc $.fn.initTabsBox
 * @namespace comp
 * @des 将 .tab-box 元素初始化为 tab 容器
 * @type function
 * @param {object=} opts 配置参数
 * @param {Array} opts.tabs tab 页
 * @param {string} opts.tabs[i].val tab 页标识
 * @param {string=} opts.tabs[i].txt tab 页标题，默认与 val 一致
 * @param {boolean=} opts.tabs[i].remove 是否可关闭，默认为 false
 * @param {string=} opts.tabs[i].width 头部宽度，默认 '120px'，scroll=false 且 tab 页显示超出范围，会引起此属性失效
 * @param {string=} opts.tabs[i].cont 对应内容部分 DOM 字符串
 * @param {string=} opts.tabs[i].url 对应内容部分 url
 * @param {boolean=} opts.tabs[i].delay 若定义了 url，此属性为 true 时将在切换时才加载内容页。默认为 false
 * @param {boolean=} opts.tabs[i].scrolling 若定义了 url，此属性为 true 时将 iframe 的 scrolling 设为 'yes'。默认为 false
 * @param {boolean=} opts.tabs[i].keepcont 删除时是否保留内容部分，默认为 false
 * @param {string=} opts.headAlign 若设为 ‘right’ 则将 tab 头部居右显示，，此时 opts.scroll 失效，不可滚动
 * @param {boolean=} opts.context 是否显示右键菜单，默认为 false
 * @param {boolean=} opts.scroll 是否支持头部超出滚动，默认为 false
 * @param {boolean=} opts.noAdjust 是否禁止监听容器尺寸变化以自动调整尺寸，默认为 false，容器尺寸不会变化时，可设为 true 以提高效率
 * @param {boolean=} opts.showAdd 是否显示添加按钮，默认为 false
 * @param {function=} opts.addHandler() 添加按钮的事件
 * @param {function=} opts.onChange(val,oldVal) 切换tab时触发事件，参数为要选中的 tab.val,原来选中的 tab.val
 * @param {function=} opts.onRemove(val) 删除tab时触发事件，参数为要删除的 tab.val
 * @return {object|undefined} obj 接口对象
 * @rtn {function} obj.refreshTab() 刷新指定val的tab页，若是由cont设置的内容，则此方法无作用
 * @rtn {function} obj.addTab(tab,noToggle) 添加 tab 页
 *       tab {object} tab 页对象，结构同 opts.head
 *       noToggle {boolean=} 添加后是否禁止切换，默认为 false，即，添加即切换
 * @rtn {function} obj.getTabs(key,value) 选中所有符合条件的 tab 列表，无条件则选择全部，未找到则返回 []
 *       key {string} tab 页对象中的键：val,txt,remove
 *       value {string=}
 * @rtn {function} obj.getTab(key,value) 选择符合条件的一个tab
 * @rtn {function} obj.removeTab(tab) 删除指定的 tab
 * @rtn {function} obj.removeAll() 删除所有 tab
 * @rtn {function} obj.selectTab(tab) 切换到指定的 tab
 * @rtn {function} obj.adjust() 手动计算绘制头部尺寸
 * @rtn {function} obj.getSelect(tab) 获取当前tab页的标识
 * @rtn {function} obj.getContEl(tab) 获取内容部分的 jquery 元素对象
 */
$.fn.initTabsBox = function(opts){
    var el = $(this);
    var CONF = {
        scrollCtrlW: 20// 左右滚动按钮宽度各为 20
        , addW: 30
        , liBefore: 0
    };
    var _returnObj;
    var contBoxEl = el.children('.tab-cont-box');
    var headBoxEl = el.children('.tab-head-box');
    opts = $.extend({
        tabs: []
        //,defaultVal:{string} 默认选中的 tabval，默认选中第一个，若定义为 false，则不选中任何 tab
        //            ,headAlign:'right'
        , context: false
        , scroll: false
        , noAdjust: false
        , showAdd: false
    }, opts);
    var _tabs = [];
    var tabGuid = opts.noAdjust ? undefined : $.generateGuid('tab');// 用于标识 window 的 resize 事件

    var _destroy = function(){
        if(headBoxEl.length){
            _tabs.length = 0;
            tabGuid && $(window).off('resize.tab_' + tabGuid);
            headBoxEl.off('click.changeTab')
                     .off('click.addTab')
                     .off('click.scroll');
            headBoxEl.remove();
        }
    };
    var tabSizes = [];// 支持滚动的状态记录 tab 头部尺寸
    var tabTotalSize = 0;
    var ulWidth = 0;// ul 可显示的尺寸
    /**
     * 重新计算 tab 头部尺寸
     * @param index {int=} 要重计算的 tab 的索引，未指定则重计算全部 tab
     * @private
     */
    var _calculateSizes = function(index){
        var lis = headBoxEl.find('.tab-head')
            , li, liBCR, item, curW;
        if(index == undefined){// 重新计算全部
            tabSizes.length = 0;
            tabTotalSize = 0;
            var len = _tabs.length;
            for(index = 0; index < len; index++){
                item = _tabs[index];
                li = lis.eq(index);
                li.css('width', item['width'] || '');
                liBCR = li[0].getBoundingClientRect();
                curW = liBCR.right - liBCR.left;
                tabSizes.push(curW);
                tabTotalSize += curW;
            }
        }
        else{
            item = _tabs[index];
            li = lis.eq(index);
            li.css('width', item['width'] || '');
            liBCR = li[0].getBoundingClientRect();
            curW = tabSizes[index];
            if(curW != undefined) tabTotalSize -= curW;
            curW = liBCR.right - liBCR.left;
            tabTotalSize += curW;
            tabSizes[index] = curW;
        }
    };
    /**
     * 根据指定项或选中项滚动
     * @param index {int=} 要滚动到视图内的 tab 索引，未定义则为当前选中项索引
     * @private
     */
    var _scrollToSeL = function(index){
        if(!headBoxEl.hasClass('tab-scroll')) return;
        var headUl = headBoxEl.find('>ul')
            , lis = headUl.children('.tab-head');
        var curLeft = 0, curRight = 0;// 选中项边界
        if(index == undefined) index = lis.index(lis.filter('.now'));
        for(var i = 0; i < tabSizes.length; i++){
            if(i == index){// 选中项
                curRight = curLeft + tabSizes[i];
                break;
            }
            curLeft += tabSizes[i];
        }
        if(headUl.is(':animated')) headUl.stop(true);
        if(curRight == 0){
            //                headUl.css({'left':CONF.scrollCtrlW+'px'});
            headUl.animate({'left': CONF.scrollCtrlW + 'px'});
        }
        else{
            var hideL = CONF.scrollCtrlW - headUl.position().left;// 左侧已被隐藏的部分的尺寸
            if(hideL > curLeft){
                //                    headUl.css({'left':-curLeft+CONF.scrollCtrlW+'px'});
                headUl.animate({'left': -curLeft + CONF.scrollCtrlW + 'px'});
            }
            else if(ulWidth + hideL - CONF.scrollCtrlW < curRight){
                //                    headUl.css({'left':ulWidth-curRight-CONF.scrollCtrlW+'px'});
                headUl.animate({'left': ulWidth - curRight - CONF.scrollCtrlW + 'px'});
            }
        }
    };
    /**
     * 滚动头部
     * @param toNext {boolean=} 向后滚动
     * @private
     */
    var _scrollHead = function(toNext){
        if(!headBoxEl.hasClass('tab-scroll')) return;
        var headUl = headBoxEl.find('>ul');
        var hideL = CONF.scrollCtrlW - headUl.position().left// 左侧已被隐藏的部分的尺寸
            , hideR = hideL + ulWidth - CONF.scrollCtrlW;// 右侧被隐藏部分前的尺寸
        var curW = 0, i, index;
        if(toNext){// 向后
            for(i = 0; i < tabSizes.length; i++){
                curW += tabSizes[i];
                if(curW > hideR){
                    index = i;
                    break;
                }
            }
        }
        else{// 向前
            for(i = 0; i < tabSizes.length; i++){
                curW += tabSizes[i];
                if(curW >= hideL){
                    index = i;
                    break;
                }
            }
        }
        if(index != undefined) _scrollToSeL(index);
    };
    var _adjust = function(){
        var headUl = headBoxEl.find('>ul');
        _calculateSizes();// 复原尺寸
        // 计算 ul 尺寸
        var headBCR = headBoxEl.eq(0)[0].getBoundingClientRect();
        ulWidth = headBCR.right - headBCR.left;
        if(opts.showAdd){// 显示添加
            ulWidth -= CONF.addW;
        }
        if(tabTotalSize != 0 && ulWidth != 0 && tabTotalSize > ulWidth){// 超出
            if(opts.scroll){
                headBoxEl.addClass('tab-scroll');
                headUl.css('width', tabTotalSize + 'px');
                var left = headUl.position().left;
                if(left > CONF.scrollCtrlW){// 左侧有留白
                    headUl.css({'left': CONF.scrollCtrlW + 'px'});
                }
                else if(tabTotalSize + left < ulWidth - CONF.scrollCtrlW){// 右侧有留白
                    headUl.css({'left': ulWidth - tabTotalSize - CONF.scrollCtrlW + 'px'});
                }
            }
            else{
                tabSizes.length && headUl.children('.tab-head').css('width', 100 / tabSizes.length + '%');
            }
        }
        else{
            if(opts.scroll){
                if(headUl.is(':animated')) headUl.stop(true);
                headUl.css('width', '');
                headBoxEl.removeClass('tab-scroll');
                headUl.css('left', 0);
            }
        }
    };
    /**
     * 添加 tab 页
     * @param tab {object} tab 页对象，结构同 opts.tabs[i]
     * @param noToggle {boolean=} 添加后是否不立即切换，默认为 false，即，添加即切换
     * @private
     */
    var _addTab = function(tab, noToggle){
        if(!headBoxEl || !tab) return;
        var val = tab.val;
        var sameTab = _getTab('val', val);
        if(sameTab){
            _selectTab(sameTab);// 选中已有项
        }
        else{
            !tab.txt && (tab.txt = tab.val);
            var txt = tab.txt
                , remove = tab.remove || false;
            var cssStr = '';
            var contStr, sScrolling;// 内容字符串
            if(tab.width) cssStr += 'width:' + tab.width + ';';
            var li = $('<li title="' + (typeof tab.title != 'undefined' ? tab.title : txt) + '" class="tab-head" data-val="' + val + '">'
                + '<div class="tab-head-item' + (remove ? ' hasrig' : '') + '" style="' + cssStr + '">'
                + txt
                + (remove ? '<div class="tab-head-remove"></div>' : '')
                + '</div></li>');
            if(opts.headAlign == 'right'){
                headBoxEl.children('ul').prepend(li);
            }
            else{
                headBoxEl.children('ul').append(li);
            }
            /* 内容部分 */
            if(tab.url){
                sScrolling = tab.scrolling === true ? 'yes' : 'no';
                if(tab.delay){
                    contStr = '<iframe width="100%" height="100%" data-name="' + tab.val + '"' +
                        ' frameborder="0" scrolling="' + sScrolling + '"></iframe>';
                }
                else{
                    contStr = '<iframe width="100%" height="100%" data-name="' + tab.val + '"' +
                        ' frameborder="0" scrolling="' + sScrolling + '" src="' + tab.url + '"></iframe>';
                }
            }
            else{
                contStr = tab.cont;
            }
            var contEl = contBoxEl.find('>.tab-cont[data-val="' + tab.val + '"]');
            if(contStr){
                if(contEl.length){
                    contEl.html(contStr);
                }
                else{
                    contBoxEl.append('<div class="tab-cont" data-val="' + val + '">' + contStr + '</div>');
                }
            }
            _tabs.push(tab);
            _calculateSizes(_tabs.length - 1);
            _adjust();
            !noToggle && headBoxEl.find('>ul>li.tab-head[data-val="' + val + '"]').click();
        }
    };
    var _getTabs = function(key, value){
        var tabs = [], i, tab;
        if(key){
            for(i = 0; i < _tabs.length; i++){
                tab = _tabs[i];
                if(tab[key] == value){
                    tabs.push(tab);
                }
            }
        }
        else{
            $.extend(tabs, _tabs);
        }
        return tabs;
    };
    var _getTab = function(key, value){
        var i, tab;
        if(key){
            for(i = 0; i < _tabs.length; i++){
                tab = _tabs[i];
                if(tab[key] == value){
                    return tab;
                }
            }
        }
    };
    var _refreshTab = function(val){
        var tab = _getTab('val', val),
            contFrame = contBoxEl.find('>.tab-cont[data-val="' + val + '"]>iframe');
        if(tab && tab.url && contFrame.length){
            //contFrame[0].contentWindow.location.reload();
            // 360 极速模式下，location.href = 'about:blank'，与 contFrame.attr(src) 不同步，直接 reload() 会显示空白页，所以改为下文实现
            contFrame.attr('src', tab.url);
        }
    };
    var _selectTab = function(tab, val){
        if(typeof tab == 'string' && val != undefined){// 根据键值查找 tab
            tab = _getTab(tab, val);
        }
        if(!tab) return;
        var headEl = headBoxEl.find('>ul>li.tab-head[data-val="' + tab.val + '"]');
        if(!headEl.hasClass('now')){// tab 未选中
            var oldHeadEl = headBoxEl.find('>ul>li.tab-head.now'),// 16.09.27 添加离开 tab 页的事件
                oldVal,
                newContEl;
            if(oldHeadEl.length){
                oldVal = oldHeadEl.attr('data-val');//data-val
                if(opts.onLeave && opts.onLeave(oldVal) === false){// onLeave 返回 false，阻止离开原来选中的 tab 页 TODO onLeave 可能为异步操作
                    return;
                }
            }
            headBoxEl.find('>ul>li.tab-head.now').removeClass('now');
            contBoxEl.find('>.tab-cont.now').removeClass('now');
            headEl.addClass('now');
            newContEl = contBoxEl.find('>.tab-cont[data-val="' + tab.val + '"]');
            // 若定义了 url 且 iframe 未定义 src，则重置 url(实现切换时延迟加载页面)
            if(tab.url && !newContEl.find('iframe').attr('src')){
                newContEl.find('iframe').attr('src', tab.url)
            }
            newContEl.addClass('now');
            opts.onChange && opts.onChange(tab.val);
        }
        _scrollToSeL();
    };
    /**
     * 删除指定的 tab
     * @param tab {object|string}
     * @param val {string|boolean=}
     * @private
     */
    var _removeTab = function(tab, val){
        if(typeof tab == 'string' && val != undefined){// 键值对指定 tab
            tab = _getTab(tab, val);
            if(!tab) return;
        }
        var headEl = headBoxEl.find('>ul>li.tab-head[data-val="' + tab.val + '"]');
        if(headEl.hasClass('now') && _tabs.length > 1){// 当前项为选中项，且还有其他标签页
            var i = _tabs.indexOf(tab);
            if(i != _tabs.length - 1){// 不是最后一项，选中后一项
                _selectTab(_tabs[i + 1]);
            }
            else{
                _selectTab(_tabs[i - 1]);
            }
        }
        var index = _tabs.indexOf(tab);
        _tabs.splice(index, 1);// 移除
        tabSizes.splice(index, 1);// 移除尺寸记录
        headEl.remove();// 移除标题
        if(!tab.keepcont){// 删除时不保留内容
            contBoxEl.find('>.tab-cont[data-val="' + tab.val + '"]').remove();
        }
        opts.onRemove && opts.onRemove(tab.val);
        _adjust();
    };
    /**
     * 删除全部 tab
     * @private
     */
    var _removeAll = function(){
        for(var i = _tabs.length - 1; i >= 0; i--){
            _removeTab(_tabs[i]);
        }
    };
    var contextVal;
    var _initContext = function(){
        var contEl = $('<div class="context"><ul>' +
            '<li data-val="closeThis"><span class="context-item">关闭当前页</span></li>' +
            '<li data-val="closeElse"><span class="context-item">关闭其他</span></li>' +
            '<li data-val="closeAll"><span class="context-item">关闭所有</span></li>' +
            '<li data-val="refresh"><span class="context-item">刷新</span></li>' +
            '</ul></div>');
        // 右键菜单
        contEl.on('click', 'li', function(){
            var type = $(this).attr('data-val');
            var tab, i, removeTabs = [];
            if(type == 'closeThis'){
                removeTabs.push(_getTab('val', contextVal));
            }
            else if(type == 'closeElse'){
                for(i = 0; i < _tabs.length; i++){
                    tab = _tabs[i];
                    if(tab.val != contextVal && tab.remove){// 不是当前项，且允许关闭
                        removeTabs.push(tab);
                    }
                }
            }
            else if(type == 'closeAll'){
                for(i = 0; i < _tabs.length; i++){
                    tab = _tabs[i];
                    if(tab.remove){// 允许关闭的项
                        removeTabs.push(tab);
                    }
                }
            }
            else if(type == 'refresh'){
                _refreshTab(contextVal);
            }
            for(i = 0; i < removeTabs.length; i++){
                _removeTab(removeTabs[i]);
            }
            contextMenu.close();
        });
        var contextMenu = headBoxEl.dropdown({
            cont: contEl
            , context: true
            , beforeShow: function(e){
                var headLi = $(e.target).closest('li');
                contEl.find('li').css('display', '');
                if(headLi.length && headBoxEl.find(headLi).length > 0){
                    contextVal = headLi.attr('data-val');
                    if(!_getTab('val', contextVal).remove){// 禁止关闭的tab页
                        contEl.find('li[data-val="closeThis"]').css('display', 'none');
                    }
                }
                else{// 不在tab页上，只显示关闭全部
                    contextVal = undefined;
                    contEl.find('li:not([data-val="closeAll"])').css('display', 'none');
                }
            }
        });
    };
    var _init = function(){
        el.addClass('tab-box');
        if(!headBoxEl.length){
            headBoxEl = $('<div class="tab-head-box clearf"><ul class="clearf"></ul>' +
                (opts.scroll ? '<div class="tab-prev"></div><div class="tab-next"></div>' : '') +
                '</div>');
        }
        if(!contBoxEl.length){
            contBoxEl = $('<div class="tab-cont-box"></div>');
        }
        headBoxEl
            .on('click.changeTab', '>ul>li.tab-head', function(){
                var head = $(this);
                var val = head.attr('data-val');
                _selectTab('val', val);
            })
            .on('click.removeTab', '.tab-head-remove', function(e){
                var tab = _getTab('val', $(this).closest('.tab-head').attr('data-val'));
                _removeTab(tab);
                e.stopPropagation();
            });
        if(opts.context){// 显示右键菜单
            _initContext();
        }
        tabGuid && $(window).on('resize.tab_' + tabGuid, _adjust);// 监听窗口 resize 事件
        el.prepend(headBoxEl);// 添加 head-box
        el.append(contBoxEl);// 添加 cont-box
        // 居右显示
        if(opts.headAlign == 'right'){
            opts.scroll = false;// TODO 居右时暂不支持滚动
            headBoxEl.children('ul').addClass('tab-heads-r');
        }
        /* 根据 opts.tabs，添加 tab 页 */
        for(var i = 0; i < opts.tabs.length; i++){
            _addTab(opts.tabs[i], true);
        }
        // 显示添加
        if(opts.showAdd){
            headBoxEl.addClass('tab-withAdd');
            headBoxEl.append('<div class="tab-add" title="新增"></div>');
            opts.addHandler && headBoxEl.on('click.addTab', '>.tab-add', function(){
                opts.addHandler();
            })
        }
        if(opts.scroll){
            headBoxEl.on('click.scroll', '.tab-prev,.tab-next', function(){
                _scrollHead($(this).hasClass('tab-next'));
            });
        }
        //opts.onInit && opts.onInit(_returnObj); TODO 是否需要扩展
        if(opts.defaultVal !== false){// 定义为 false 时不选中任何 tab 页
            if(typeof opts.defaultVal == 'undefined'){
                headBoxEl.find('li.tab-head').eq(0).click();// 默认选中第一项
            }
            else{
                headBoxEl.find('li.tab-head[data-val="' + opts.defaultVal + '"]').click();// 默认选中第一项
            }
        }
    };
    _returnObj = {
        refreshTab: _refreshTab
        , addTab: _addTab
        , getTabs: _getTabs
        , getTab: _getTab
        , removeTab: _removeTab
        , removeAll: _removeAll
        , selectTab: _selectTab
        , adjust: _adjust
        , getSelect: function(){
            return _getTab('val', headBoxEl.find('>ul>li.now').attr('data-val'));
        }
        , getContEl: function(tab){
            return contBoxEl.find('>.tab-cont[data-val="' + tab.val + '"]');
        }
    };
    _destroy();
    _init();
    return _returnObj;
};